import { defineGlobalProperty, generateId, isMyRoom, isOfficialShard, isRoomInterval } from '@/ayaka'
import TransportTaskManager from '../task/base/transport'
import { OneToOneTransportData } from '../task/base/transport/types'
import { allResource } from './view'
import { StorageResourceStandard } from '@/setting'
import MarketManager from '@/modules/market'
import { ResourceTopPrice } from '@/modules/market/constants'
import { ResourceMemory, SellResourceTask, SendResourceTask } from './types'
import { resourceList } from './constants'
import PCTaskManager from '../task/pc'
import UpgradeTaskManager from '../task/base/upgrade'

/**
 * 资源管理器
 */
export default class ResourceManager {
    // 搬运发送资源任务名字
    public static readonly SEND_RESOURCE_TASK_NAME = '搬运发送资源'

    // 仓库最低空闲容量
    public static readonly STORAGE_MIN_FREE_CAPACITY = 30000

    // 终端最低空闲容量
    public static readonly TERMINAL_MIN_FREE_CAPACITY = 30000

    // 可以自动出售的资源
    public static readonly AUTO_SELL_RESOURCE: { [type in ResourceConstant]?: number } = {
        power: 50000,
        H: 30000,
        O: 30000,
        K: 30000,
        L: 30000,
        Z: 30000,
        U: 30000,
        X: 30000,
    }

    /**
     * 运行
     */
    public static run(room: MyRoom) {
        const memory = ResourceManager.getMemory(room)

        ResourceManager.balanceStorageAndTerminal(room)
        ResourceManager.sendTaskManager(room, memory)
        ResourceManager.sellTaskManager(room, memory)
        ResourceManager.requestResource(room)
        ResourceManager.extendStorage(room)
    }

    /**
     * 获取 memory
     */
    public static getMemory(room: MyRoom) {
        if (!room.memory.resource) {
            room.memory.resource = {
                sendTasks: [],
                sellTasks: [],
            }
        }
        // 兼容
        if (!room.memory.resource.sellTasks) room.memory.resource.sellTasks = []
        return room.memory.resource
    }

    /**
     * 平衡 storage 和 terminal 之间的资源
     */
    public static balanceStorageAndTerminal(room: MyRoom) {
        if (!isRoomInterval(room, 63)) return
        const storage = room.storage
        const terminal = room.terminal
        if (!storage || !terminal) return

        if (storage.store.getFreeCapacity() <= 100e3 && terminal.store.getFreeCapacity() >= 30000) {
            ResourceManager.cleanStorage(room, storage)
        }

        // storage 中必须有足够空间存放能量，否则不进行平衡
        let freeSpace =
            storage.store.getFreeCapacity() -
            Math.max(StorageResourceStandard['energy'][0] - storage.store['energy'], 30000)

        for (const resourceType of new Set([...Object.keys(terminal.store), ...Object.keys(StorageResourceStandard)])) {
            // 有资源发送或者转移任务时不进行平衡
            if (
                ResourceManager.getSendTaskByType(room, resourceType as ResourceConstant).length ||
                ResourceManager.getSellTaskByType(room, resourceType as ResourceConstant).length ||
                TransportTaskManager.searchTransportTaskBySubName(room, `ttos-${resourceType}`).length
            ) {
                continue
            }

            if (resourceType in StorageResourceStandard) {
                const type = resourceType as keyof typeof StorageResourceStandard
                const [min, max] = StorageResourceStandard[type]

                let amount: number
                if (type === 'energy') {
                    const isQuickUpgrade = UpgradeTaskManager.isQuickUpgrade(room)

                    // 自动出售能量
                    if (
                        (storage.store[type] > min || storage.store.getFreeCapacity() < 30000) &&
                        terminal.store[type] > 80000
                    ) {
                        // 冲级时不出售能量
                        if (isQuickUpgrade) continue

                        MarketManager.deal(room.name, type, ORDER_BUY, 15000, {
                            minPrice: MarketManager.getTopPrice(type) / 2,
                            minAmount: 5000,
                            range: 20 + Math.floor(terminal.store[type] / 10e3),
                        })
                        continue
                    }

                    if (storage.store[type] > min) continue

                    if (terminal.store[type] < (isQuickUpgrade ? 80000 : 45000)) {
                        if (terminal.store.getFreeCapacity() < 10000) continue

                        let rate = 0.985
                        const isUrgent = storage.store[type] + terminal.store[type] < 50000
                        if (isUrgent) rate = 0.995
                        if (isQuickUpgrade) rate = 1

                        const amount = isQuickUpgrade ? 50000 : isUrgent ? 30000 : 10000

                        // 官服
                        if (isOfficialShard()) {
                            // 购买
                            MarketManager.autoBuy(
                                room.name,
                                type,
                                amount,
                                MarketManager.getTopPrice('energy') * rate + 0.001,
                            )
                        } else {
                            MarketManager.deal(room.name, type, ORDER_SELL, amount)
                        }

                        continue
                    }

                    amount = Math.min(
                        terminal.store[type] - 30000,
                        (min + max) / 2 - storage.store[type],
                        storage.store.getFreeCapacity(type),
                    )
                } else {
                    if (freeSpace <= 0) continue

                    if (storage.store[type] < min && terminal.store[type] < 3000) {
                        if (terminal.store.getFreeCapacity() < 50000) continue
                        if (type === 'power' && room.controller.level < 8) continue
                        // 购买
                        if (isOfficialShard()) {
                            MarketManager.autoBuy(room.name, type, 10000)
                        } else {
                            // 私服主动 deal
                            MarketManager.deal(room.name, type, ORDER_SELL, Math.min(10000, freeSpace))
                        }
                        continue
                    }

                    amount = Math.min(terminal.store[type], 9000, freeSpace)
                    freeSpace -= amount
                }
                if (amount) ResourceManager.terminalTransferToStorage(room, type, amount, `ttos-${type}`)
            } else {
                if (freeSpace <= 0) continue
                const type = resourceType as ResourceConstant
                if (ResourceTopPrice[type] > 500 || terminal.store[type] > 3000) {
                    const amount = Math.min(terminal.store[type], freeSpace, 30000)
                    freeSpace -= amount
                    ResourceManager.terminalTransferToStorage(room, type, amount, `ttos-${type}`)
                }
            }
        }
    }

    /**
     * 清理 storage 资源，腾出空间
     */
    public static cleanStorage(room: MyRoom, storage: StructureStorage) {
        // 有storage 和 terminal 之间的资源转移任务
        if (
            TransportTaskManager.searchTransportTaskBySubName(room, 'ttos').length ||
            TransportTaskManager.searchTransportTaskBySubName(room, 'stot').length
        ) {
            return
        }

        // 自动出售的资源类型，按照资源数量从大到小排序
        const sellTypes = Object.keys(ResourceManager.AUTO_SELL_RESOURCE)
            .filter((type: ResourceConstant) => storage.store[type] > ResourceManager.AUTO_SELL_RESOURCE[type]!)
            .sort(
                (a: ResourceConstant, b: ResourceConstant) => storage.store[b] - storage.store[a],
            ) as ResourceConstant[]

        for (const resourceType of sellTypes) {
            // 有资源发送或者出售任务
            if (
                ResourceManager.getSendTaskByType(room, resourceType).length ||
                ResourceManager.getSellTaskByType(room, resourceType).length
            )
                continue

            if (resourceType in StorageResourceStandard) {
                // 有数量限制的资源，如果少于最大值则不清理
                const [_, max] = StorageResourceStandard[resourceType as keyof typeof StorageResourceStandard]
                if (storage.store[resourceType] < max) continue
            }

            // 搬运到终端自动出售
            ResourceManager.storageTransferToTerminal(room, resourceType, 9000)
            ResourceManager.addSellTask(room, resourceType, 9000, { method: 'deal' })
            break
        }

        // 转移多余资源到其他房间
        if (!room.memory.resource.sendTasks.length) {
            const freeRoom = ResourceManager.findFreeSpaceRoom()[0]
            if (freeRoom) {
                const sendTypes = Object.keys(storage.store)
                    .filter((type: ResourceConstant) => {
                        if (type in ResourceManager.AUTO_SELL_RESOURCE || type === 'energy') return false

                        return storage.store[type] >= 30000
                    })
                    .sort((a: ResourceConstant, b: ResourceConstant) => storage.store[b] - storage.store[a])
                if (sendTypes.length) {
                    ResourceManager.addSendTask(room, freeRoom.name, sendTypes[0] as ResourceConstant, 6000)
                }
            }
        }
    }

    /**
     * terminal 向 storage 中转移资源
     */
    public static terminalTransferToStorage(
        room: MyRoom,
        resourceType: ResourceConstant,
        amount: number,
        name?: string,
    ) {
        if (!room.terminal || !room.storage) return
        if (name && TransportTaskManager.searchTransportTaskByName(room, name).length) return
        name = name || `ttos-${resourceType}`

        const data: OneToOneTransportData = {
            sourceId: room.terminal.id,
            targetId: room.storage.id,
            resInfo: {
                [resourceType]: {
                    require: amount,
                    has: 0,
                },
            },
        }
        TransportTaskManager.addOneToOneTransportTask(room, name, data, undefined, 'ttos')
    }

    /**
     * storage 向 terminal 中转移资源
     */
    public static storageTransferToTerminal(
        room: MyRoom,
        resourceType: ResourceConstant,
        amount: number,
        name?: string,
    ) {
        if (!room.terminal || !room.storage) return
        if (name && TransportTaskManager.searchTransportTaskByName(room, name).length) return
        name = name || `stot-${resourceType}`

        const data: OneToOneTransportData = {
            sourceId: room.storage.id,
            targetId: room.terminal.id,
            resInfo: {
                [resourceType]: {
                    require: amount,
                    has: 0,
                },
            },
        }
        TransportTaskManager.addOneToOneTransportTask(room, name, data, undefined, 'stot')
    }

    /**
     * 添加发送任务
     */
    public static addSendTask(room: MyRoom, roomName: string, type: ResourceConstant, amount: number) {
        // 任何时候都不要发送能量
        if (type === 'energy') {
            return false
        }

        const task: SendResourceTask = {
            id: generateId(),
            roomName,
            type,
            amount,
        }

        const memory = ResourceManager.getMemory(room)
        memory.sendTasks.push(task)
        return true
    }

    /**
     * 移除发送任务
     */
    public static deleteSendTask(room: MyRoom, taskId: string) {
        const memory = ResourceManager.getMemory(room)
        memory.sendTasks = memory.sendTasks.filter((task) => task.id !== taskId)
    }

    /**
     * 获取发送任务
     */
    public static getSendTaskById(room: MyRoom, taskId: string) {
        const memory = ResourceManager.getMemory(room)
        return memory.sendTasks.find((task) => task.id === taskId)
    }

    /**
     * 获取发送任务
     */
    public static getSendTaskByType(room: MyRoom, type: ResourceConstant) {
        const memory = ResourceManager.getMemory(room)
        return memory.sendTasks.filter((task) => task.type === type)
    }

    /**
     * 发送任务管理
     */
    public static sendTaskManager(room: MyRoom, memory: ResourceMemory) {
        const { sendTasks } = memory

        if (!sendTasks.length || !room.terminal || !room.storage) return

        const task = sendTasks[0]

        if (task.timeout === 0) {
            ResourceManager.deleteSellTask(room, task.id)
            return
        } else if (task.timeout) {
            task.timeout--
        }

        if (task.waitTime) {
            task.waitTime--
            return
        }

        ResourceManager.executeSendTask(room, task)
    }

    /**
     * 执行发送任务
     */
    public static executeSendTask(room: MyRoom, task: SendResourceTask) {
        const terminal = room.terminal!
        const storage = room.storage!

        const { roomName, type, amount } = task

        if (amount <= 0) {
            ResourceManager.deleteSendTask(room, task.id)
            return
        }

        // 正在搬运发送资源
        if (TransportTaskManager.searchTransportTaskByName(room, ResourceManager.SEND_RESOURCE_TASK_NAME).length) {
            return
        }

        const cost = Game.market.calcTransactionCost(amount, room.name, roomName)

        // 无搬运任务，检查终端，发送资源
        if (terminal.store[type] > 0) {
            if (terminal.cooldown) return

            if (terminal.store['energy'] < 1000) {
                task.waitTime = 100
                return
            }

            const sendAmount = Math.min(
                amount,
                terminal.store[type],
                Math.floor((terminal.store['energy'] / cost) * amount),
            )
            const result = terminal.send(
                type,
                sendAmount,
                roomName,
                `${global.ayaka.myName} 发送 ${type} ${sendAmount}`,
            )
            if (result === OK) {
                task.amount -= sendAmount
            }

            return
        }

        // 仓库能量不够，等待
        if (terminal.store['energy'] < 30000 && storage.store['energy'] < 15000) {
            task.waitTime = 100
            return
        }

        if (storage.store[type] <= 0) {
            ResourceManager.deleteSendTask(room, task.id)
            return
        }

        const sendAmount = Math.min(
            Math.floor(terminal.store.getFreeCapacity() * (amount / (amount + cost))),
            amount,
            storage.store[type],
        )
        const transportData: OneToOneTransportData = {
            sourceId: storage.id,
            targetId: terminal.id,
            resInfo: {
                [type]: {
                    require: sendAmount,
                    has: 0,
                },
                ...(storage.store['energy'] >= 15000
                    ? {
                          energy: {
                              require: Math.min(
                                  Math.ceil(sendAmount * (cost / (amount + cost))),
                                  storage.store['energy'] - 5000,
                              ),
                              has: 0,
                          },
                      }
                    : {}),
            },
        }
        TransportTaskManager.addOneToOneTransportTask(room, ResourceManager.SEND_RESOURCE_TASK_NAME, transportData)
    }

    /**
     * 添加出售任务
     */
    public static addSellTask(
        room: MyRoom,
        type: ResourceConstant,
        amount: number,
        opts: Partial<SellResourceTask> = {},
    ) {
        const task: SellResourceTask = {
            id: generateId(),
            type,
            amount,
            ...opts,
        }

        const memory = ResourceManager.getMemory(room)
        memory.sellTasks.push(task)
        return true
    }

    /**
     * 移除出售任务
     */
    public static deleteSellTask(room: MyRoom, taskId: string) {
        const memory = ResourceManager.getMemory(room)
        memory.sellTasks = memory.sellTasks.filter((task) => task.id !== taskId)
    }

    /**
     * 获取出售任务
     */
    public static getSellTaskById(room: MyRoom, taskId: string) {
        const memory = ResourceManager.getMemory(room)
        return memory.sellTasks.find((task) => task.id === taskId)
    }

    /**
     * 获取出售任务
     */
    public static getSellTaskByType(room: MyRoom, type: ResourceConstant) {
        const memory = ResourceManager.getMemory(room)
        return memory.sellTasks.filter((task) => task.type === type)
    }

    /**
     * 出售任务管理
     */
    public static sellTaskManager(room: MyRoom, memory: ResourceMemory) {
        const { sellTasks } = memory

        if (!sellTasks.length || !room.terminal) return

        const task = sellTasks[0]
        if (task.timeout === 0) {
            ResourceManager.deleteSellTask(room, task.id)
            return
        } else if (task.timeout) {
            task.timeout--
        }

        ResourceManager.executeSellTask(room, task)
    }

    /**
     * 执行出售任务
     */
    public static executeSellTask(room: MyRoom, task: SellResourceTask) {
        const terminal = room.terminal!
        const storage = room.storage
        if (terminal.cooldown || !isRoomInterval(room, 11)) return

        const { type, amount, method = 'deal', minDealPrice } = task
        const sellAmount = Math.min(amount, terminal.store[type])
        if (sellAmount > 0) {
            if (method === 'deal') {
                const [result, realAmount] = MarketManager.deal(room.name, type, ORDER_BUY, sellAmount, {
                    minAmount: Math.floor(sellAmount / 100),
                    minPrice: minDealPrice,
                })
                if (result === OK) {
                    task.amount -= realAmount
                }
            } else {
                //
            }
        } else if (storage) {
            const requireAmount = amount - terminal.store[type]
            if (storage.store[type] < requireAmount) {
                ResourceManager.deleteSellTask(room, task.id)
                return
            }

            if (
                requireAmount > 0 &&
                !TransportTaskManager.searchTransportTaskByName(room, `ttos-${type}`).length &&
                !TransportTaskManager.searchTransportTaskByName(room, `stot-${type}`).length
            ) {
                ResourceManager.storageTransferToTerminal(room, type, requireAmount)
            }
        }

        if (task.amount <= 0) {
            ResourceManager.deleteSellTask(room, task.id)
            return
        }
    }

    /**
     * 查看资源
     */
    public static view(roomName?: string) {
        allResource(roomName)
    }

    /**
     * 请求其他房间的资源
     */
    public static requestResource(room: MyRoom) {
        if (!room.storage || !room.terminal || !isRoomInterval(room, 150)) return

        const getTargetRoom = (type: ResourceConstant, amount: number) => {
            return Object.values(Game.rooms).find(
                (r) =>
                    isMyRoom(r) &&
                    r.terminal &&
                    r.storage &&
                    r.memory.center &&
                    r.storage.store[type] >= amount &&
                    !ResourceManager.getSendTaskByType(r, type).length,
            ) as MyRoom
        }

        for (const resourceType of [...resourceList.bar, 'power']) {
            const type = resourceType as ResourceConstant
            const has = room.storage.store[type] + room.terminal.store[type]
            if (has > 18000) continue

            const targetRoom = getTargetRoom(type, 30000)
            if (!targetRoom) continue

            ResourceManager.addSendTask(targetRoom, room.name, type, 7500)
        }

        for (const resourceType of ['XUH2O', 'XZHO2', 'XKHO2']) {
            const type = resourceType as ResourceConstant
            const has = room.storage.store[type] + room.terminal.store[type]
            if (has >= 8000) continue

            const targetRoom = getTargetRoom(type, 21000)
            if (!targetRoom) continue

            ResourceManager.addSendTask(targetRoom, room.name, type, 4500)
        }
    }

    /**
     * 找到有空闲空间房间
     */
    public static findFreeSpaceRoom() {
        if (Game._freeSpaceRooms) return Game._freeSpaceRooms
        return (Game._freeSpaceRooms = Object.values(Game.rooms)
            .filter(
                (room) =>
                    isMyRoom(room) &&
                    room.controller.level >= 6 &&
                    room.storage &&
                    room.terminal &&
                    room.storage.store.getFreeCapacity() >= 150e3,
            )
            .sort((r1, r2) => r2.storage!.store.getFreeCapacity() - r1.storage!.store.getFreeCapacity()) as MyRoom[])
    }

    /**
     * 仓库扩容
     */
    public static extendStorage(room: MyRoom) {
        if (room.storage && room.storage.store.getUsedCapacity() > 950e3) {
            PCTaskManager.autoAddTask(room, PWR_OPERATE_STORAGE, room.storage, 50, 10)
        }
    }
}

defineGlobalProperty('Res', {
    value: ResourceManager,
})
